/*
	Masked Input plugin for jQuery
	Copyright (c) 2007-2013 Josh Bush (digitalbush.com)
	Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license)
	Version: 1.3.1
 */
(function($) {
	function getPasteEvent() {
		var el = document.createElement('input'), name = 'onpaste';
		el.setAttribute(name, '');
		return (typeof el[name] === 'function') ? 'paste' : 'input';
	}

	var pasteEventName = getPasteEvent() + ".mask", ua = navigator.userAgent, iPhone = /iphone/i
			.test(ua), android = /android/i.test(ua), caretTimeoutId;

	$.mask = {
		// Predefined character definitions
		definitions : {
			'9' : "[0-9]",
			'a' : "[A-Za-z]",
			'*' : "[A-Za-z0-9]"
		},
		dataName : "rawMaskFn",
		placeholder : '_',
	};

	$.fn
			.extend({
				// Helper Function for Caret positioning
				caret : function(begin, end) {
					var range;

					if (this.length === 0 || this.is(":hidden")) {
						return;
					}

					if (typeof begin == 'number') {
						end = (typeof end === 'number') ? end : begin;
						return this.each(function() {
							if (this.setSelectionRange) {
								this.setSelectionRange(begin, end);
							} else if (this.createTextRange) {
								range = this.createTextRange();
								range.collapse(true);
								range.moveEnd('character', end);
								range.moveStart('character', begin);
								range.select();
							}
						});
					} else {
						if (this[0].setSelectionRange) {
							begin = this[0].selectionStart;
							end = this[0].selectionEnd;
						} else if (document.selection
								&& document.selection.createRange) {
							range = document.selection.createRange();
							begin = 0 - range.duplicate().moveStart(
									'character', -100000);
							end = begin + range.text.length;
						}
						return {
							begin : begin,
							end : end
						};
					}
				},
				unmask : function() {
					return this.trigger("unmask");
				},
				mask : function(mask, settings) {
					var input, defs, tests, partialPosition, firstNonMaskPos, len;

					if (!mask && this.length > 0) {
						input = $(this[0]);
						return input.data($.mask.dataName)();
					}
					settings = $.extend({
						placeholder : $.mask.placeholder, // Load default
						// placeholder
						completed : null
					}, settings);

					defs = $.mask.definitions;
					tests = [];
					partialPosition = len = mask.length;
					firstNonMaskPos = null;

					$.each(mask.split(""), function(i, c) {
						if (c == '?') {
							len--;
							partialPosition = i;
						} else if (defs[c]) {
							tests.push(new RegExp(defs[c]));
							if (firstNonMaskPos === null) {
								firstNonMaskPos = tests.length - 1;
							}
						} else {
							tests.push(null);
						}
					});

					return this
							.trigger("unmask")
							.each(
									function() {
										var input = $(this), buffer = $
												.map(
														mask.split(""),
														function(c, i) {
															if (c != '?') {
																return defs[c] ? settings.placeholder
																		: c;
															}
														}), focusText = input
												.val();

										function seekNext(pos) {
											while (++pos < len && !tests[pos])
												;
											return pos;
										}

										function seekPrev(pos) {
											while (--pos >= 0 && !tests[pos])
												;
											return pos;
										}

										function shiftL(begin, end) {
											var i, j;

											if (begin < 0) {
												return;
											}

											for (i = begin, j = seekNext(end); i < len; i++) {
												if (tests[i]) {
													if (j < len
															&& tests[i]
																	.test(buffer[j])) {
														buffer[i] = buffer[j];
														buffer[j] = settings.placeholder;
													} else {
														break;
													}

													j = seekNext(j);
												}
											}
											writeBuffer();
											input.caret(Math.max(
													firstNonMaskPos, begin));
										}

										function shiftR(pos) {
											var i, c, j, t;

											for (i = pos,
													c = settings.placeholder; i < len; i++) {
												if (tests[i]) {
													j = seekNext(i);
													t = buffer[i];
													buffer[i] = c;
													if (j < len
															&& tests[j].test(t)) {
														c = t;
													} else {
														break;
													}
												}
											}
										}

										function keydownEvent(e) {
											var k = e.which, pos, begin, end;

											// backspace, delete, and escape get
											// special treatment
											if (k === 8 || k === 46
													|| (iPhone && k === 127)) {
												pos = input.caret();
												begin = pos.begin;
												end = pos.end;

												if (end - begin === 0) {
													begin = k !== 46 ? seekPrev(begin)
															: (end = seekNext(begin - 1));
													end = k === 46 ? seekNext(end)
															: end;
												}
												clearBuffer(begin, end);
												shiftL(begin, end - 1);

												e.preventDefault();
											} else if (k == 27) {// escape
												input.val(focusText);
												input.caret(0, checkVal());
												e.preventDefault();
											}
										}

										function keypressEvent(e) {
											var k = e.which, pos = input
													.caret(), p, c, next;

											if (e.ctrlKey || e.altKey
													|| e.metaKey || k < 32) {// Ignore
												return;
											} else if (k) {
												if (pos.end - pos.begin !== 0) {
													clearBuffer(pos.begin,
															pos.end);
													shiftL(pos.begin,
															pos.end - 1);
												}

												p = seekNext(pos.begin - 1);
												if (p < len) {
													c = String.fromCharCode(k);
													if (tests[p].test(c)) {
														shiftR(p);

														buffer[p] = c;
														writeBuffer();
														next = seekNext(p);

														if (android) {
															setTimeout(
																	$
																			.proxy(
																					$.fn.caret,
																					input,
																					next),
																	0);
														} else {
															input.caret(next);
														}

														if (settings.completed
																&& next >= len) {
															settings.completed
																	.call(input);
														}
													}
												}
												e.preventDefault();
											}
										}

										function clearBuffer(start, end) {
											var i;
											for (i = start; i < end && i < len; i++) {
												if (tests[i]) {
													buffer[i] = settings.placeholder;
												}
											}
										}

										function writeBuffer() {
											input.val(buffer.join(''));
										}

										function checkVal(allow) {
											// try to place characters where
											// they belong
											var test = input.val(), lastMatch = -1, i, c;

											for (i = 0, pos = 0; i < len; i++) {
												if (tests[i]) {
													buffer[i] = settings.placeholder;
													while (pos++ < test.length) {
														c = test
																.charAt(pos - 1);
														if (tests[i].test(c)) {
															buffer[i] = c;
															lastMatch = i;
															break;
														}
													}
													if (pos > test.length) {
														break;
													}
												} else if (buffer[i] === test
														.charAt(pos)
														&& i !== partialPosition) {
													pos++;
													lastMatch = i;
												}
											}
											if (allow) {
												writeBuffer();
											} else if (lastMatch + 1 < partialPosition) {
												input.val("");
												clearBuffer(0, len);
											} else {
												writeBuffer();
												input.val(input.val()
														.substring(0,
																lastMatch + 1));
											}
											return (partialPosition ? i
													: firstNonMaskPos);
										}

										input
												.data(
														$.mask.dataName,
														function() {
															return $
																	.map(
																			buffer,
																			function(
																					c,
																					i) {
																				return tests[i]
																						&& c != settings.placeholder ? c
																						: null;
																			})
																	.join('');
														});

										if (!input.attr("readonly"))
											input
													.one(
															"unmask",
															function() {
																input
																		.unbind(
																				".mask")
																		.removeData(
																				$.mask.dataName);
															})
													.bind(
															"focus.mask",
															function() {
																clearTimeout(caretTimeoutId);
																var pos, moveCaret;

																focusText = input
																		.val();
																pos = checkVal();

																caretTimeoutId = setTimeout(
																		function() {
																			writeBuffer();
																			if (pos == mask.length) {
																				input
																						.caret(
																								0,
																								pos);
																			} else {
																				input
																						.caret(pos);
																			}
																		}, 10);
															})
													.bind(
															"blur.mask",
															function() {
																checkVal();
																if (input.val() != focusText)
																	input
																			.change();
															})
													.bind("keydown.mask",
															keydownEvent)
													.bind("keypress.mask",
															keypressEvent)
													.bind(
															pasteEventName,
															function() {
																setTimeout(
																		function() {
																			var pos = checkVal(true);
																			input
																					.caret(pos);
																			if (settings.completed
																					&& pos == input
																							.val().length)
																				settings.completed
																						.call(input);
																		}, 0);
															});
										checkVal(); // Perform initial check for
										// existing values
									});
				}
			});

})(jQuery);